home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / tagsgen.exe / CTAG.C < prev    next >
C/C++ Source or Header  |  1992-03-28  |  74KB  |  2,057 lines

  1. /*
  2.  EPSHeader
  3.  
  4.    File: ctag.c
  5.    Author: J. Kercheval
  6.    Created: Sun, 07/14/1991  17:24:44
  7. */
  8. /*
  9.  EPSRevision History
  10.  
  11.    J. Kercheval  Sat, 07/27/1991  22:08:04  creation
  12.    J. Kercheval  Sun, 08/18/1991  20:58:13  completion of CGetToken()
  13.    J. Kercheval  Wed, 08/21/1991  22:34:49  place function recognition
  14.    J. Kercheval  Wed, 08/21/1991  23:11:17  add defines and macros
  15.    J. Kercheval  Wed, 08/21/1991  23:54:33  add typedef and class parsing
  16.    J. Kercheval  Thu, 08/22/1991  23:53:51  add global variables
  17.    J. Kercheval  Thu, 08/22/1991  23:54:05  add enum, struct, union
  18.    J. Kercheval  Thu, 08/22/1991  23:54:28  add globals via typedefs
  19.    J. Kercheval  Sun, 08/25/1991  23:09:28  complete semantic parser
  20.    J. Kercheval  Tue, 08/27/1991  23:28:34  fix bug in typedef, struct, enum and union declarations
  21.    J. Kercheval  Sat, 08/31/1991  23:58:03  add prototype parsing
  22.    J. Kercheval  Tue, 09/03/1991  22:28:55  move many macros to functions
  23.    J. Kercheval  Tue, 09/03/1991  23:05:34  clean code and consolidate to functions
  24.    J. Kercheval  Wed, 09/04/1991  00:16:21  add GNU tag output format support
  25.    J. Kercheval  Sun, 09/08/1991  13:24:53  minor bug fix in function and global variable parser
  26.    J. Kercheval  Sun, 09/08/1991  21:31:06  fix bug in lexical parser
  27.    J. Kercheval  Mon, 09/09/1991  21:49:19  fix bug in function parser
  28.    J. Kercheval  Mon, 09/09/1991  22:39:12  fix buf in define parser
  29.    J. Kercheval  Tue, 09/10/1991  22:06:09  fix typedef parser
  30.    J. Kercheval  Wed, 09/11/1991  02:04:48  add extern symbol recognition
  31.    J. Kercheval  Wed, 09/11/1991  19:49:11  fix bug in function pointer variable declaration
  32.    J. Kercheval  Wed, 09/11/1991  20:38:13  add support for function pointer variable declarations after first declaration
  33.    J. Kercheval  Wed, 09/11/1991  21:51:37  move #directive parsing between semantic and lexical parser
  34.    J. Kercheval  Thu, 09/12/1991  22:44:43  add support for #ifdef blocks to avoid unmatched parens in ToLevelZero parsing
  35.    J. Kercheval  Wed, 09/18/1991  22:05:02  fix bug in GetToken and DiscardLine
  36.    J. Kercheval  Thu, 09/19/1991  22:26:09  fix bug in lexical parser when parsing non C syntax files
  37.    J. Kercheval  Thu, 10/03/1991  18:15:10  add support for Static declarations
  38.    J. Kercheval  Fri, 10/04/1991  11:13:23  add support for tagging enumeration constants
  39.    J. Kercheval  Mon, 10/07/1991  09:36:07  create CParseEnumerationConstants()
  40.    J. Kercheval  Tue, 11/12/1991  21:46:25  add junk filter on token output
  41.    J. Kercheval  Sat, 03/28/1992  13:50:06  fix a few bugs and add extern "C" parsing
  42. */
  43.  
  44. #include <string.h>
  45.  
  46. #include "ctag.h"
  47. #include "tagio.h"
  48. #include "log.h"
  49.  
  50. #define CBUFSIZE 4096
  51. #define MAX_TOKEN_LENGTH 4096
  52.  
  53.  
  54. /* function for determining if character is whitespace */
  55. #define IsWhite(c) ( _C_white_table[c] )
  56.  
  57. /* the indexed table for white space character lookup */
  58. BOOLEAN _C_white_table[256];
  59.  
  60. /* list of whitespace characters */
  61. char C_white[] = " \f\t\v\n\r";
  62.  
  63.  
  64. /* function for determining if character is a delimiter */
  65. #define IsDelim(c) ( _C_delim_table[c] )
  66.  
  67. /* the indexed table for token delimiter lookup */
  68. BOOLEAN _C_delim_table[256];
  69.  
  70. /* list of token delimiters */
  71. char C_delim[] = " \f\t\v\n\r\"[](){}#;:,.'=-+*/%&|^~!<>?";
  72.  
  73.  
  74. /* function for determining if character is a puncuator */
  75. #define IsPunctuator(c) ( _C_punctuator_table[c] )
  76.  
  77. /* the indexed table for punctuator character lookup */
  78. BOOLEAN _C_punctuator_table[256];
  79.  
  80. /* list of punctuators */
  81. char C_punctuator[] = "[](){},;=";
  82.  
  83. /*
  84.  * symbol type information is tied to the switches in flags in CTags().  This
  85.  * enum is used to denote the type of the current tag for determining where
  86.  * the appropriate name is located
  87.  */
  88. enum SymbolTypeEnum {
  89.     NOP, Function, ProtoType, Structure, TypeDefinition, Macro,
  90.     Enumeration, EnumerationConstant, Union, GlobalVariable, Class,
  91.     Define, Extern, Static
  92. };
  93.  
  94. /* convenient definition */
  95. typedef enum SymbolTypeEnum SymbolType;
  96.  
  97. /* the current file buffer state */
  98. typedef struct BufferStruct {
  99.     char Cbuf[CBUFSIZE + 1];    /* input buffer for get_token routine */
  100.     char *buffer;               /* current index into the pointer */
  101.     long int token_char_location;       /* current token char location */
  102.     long int token_line_location;       /* current token line in buffer */
  103.     long int token_line_offset; /* offset of current line */
  104.     FILE *infile;
  105. } Buffer;
  106.  
  107.  
  108. /* the current input token state */
  109. typedef struct TokenStruct {
  110.     char sbuf1[MAX_TOKEN_LENGTH];       /* the first token buffer */
  111.     long int charloc1;          /* the char location of sbuf1 */
  112.     long int tokenline1;        /* the line number of sbuf1 */
  113.     long int lineoffset1;       /* the line offset of sbuf1 */
  114.  
  115.     char sbuf2[MAX_TOKEN_LENGTH];       /* the second token buffer */
  116.     long int charloc2;          /* the char location of sbuf2 */
  117.     long int tokenline2;        /* the line number of sbuf2 */
  118.     long int lineoffset2;       /* the line offset of sbuf2 */
  119.  
  120.     char *cur_token;            /* pointer to the current token buffer */
  121.     long int *cur_char_location;/* the location of current token */
  122.     long int *cur_token_line;   /* the line of the current token */
  123.     long int *cur_line_offset;  /* the line offset of the current token */
  124.  
  125.     char *prev_token;           /* pointer to the last token buffer */
  126.     long int *prev_char_location;       /* the location of previous token */
  127.     long int *prev_token_line;  /* the line of the previous token */
  128.     long int *prev_line_offset; /* the line offset of the previous token */
  129.  
  130.     int token_count;            /* tokens seen since last */
  131.     int else_nesting_level;     /* levels deep in #else/#elif nest */
  132.  
  133.     BOOLEAN extern_active;      /* minor state for this statement */
  134.     BOOLEAN CPP_extern_active;  /* minor state for this statement */
  135.     BOOLEAN static_active;      /* minor state for this statement */
  136. } Token;
  137.  
  138.  
  139. /*----------------------------------------------------------------------------
  140.  *
  141.  * CParserInit() initializes the tables required by the parser. The tables
  142.  * used are a simple boolean index which are true if the character
  143.  * corresponding to the index is a member of the associated table.
  144.  *
  145.  ---------------------------------------------------------------------------*/
  146.  
  147. void CParserInit()
  148. {
  149.     char *s;
  150.     int i;
  151.  
  152.     /* init the entire block to FALSE */
  153.     for (i = 0; i < 256; i++) {
  154.         _C_delim_table[i] = FALSE;
  155.         _C_white_table[i] = FALSE;
  156.         _C_punctuator_table[i] = FALSE;
  157.     }
  158.  
  159.     /* set the characters in the delim set to TRUE */
  160.     for (s = C_delim; *s; s++) {
  161.         _C_delim_table[*s] = TRUE;
  162.     }
  163.  
  164.     /* set the characters in the white set to TRUE */
  165.     for (s = C_white; *s; s++) {
  166.         _C_white_table[*s] = TRUE;
  167.     }
  168.  
  169.     /* set the characters in the punctuator set to TRUE */
  170.     for (s = C_punctuator; *s; s++) {
  171.         _C_punctuator_table[*s] = TRUE;
  172.     }
  173. }
  174.  
  175.  
  176. /*----------------------------------------------------------------------------
  177.  *
  178.  * CSymbolWanted() returns true if flags are true for the symbol type passed
  179.  * and false otherwise.  The following mapping is done:
  180.  *
  181.  *      Flag        Type
  182.  *      ---------   --------------
  183.  *      flags->cf   FunctionCall
  184.  *      flags->cp   ProtoType
  185.  *      flags->cs   Structure
  186.  *      flags->ct   TypeDefinition
  187.  *      flags->cm   Macro
  188.  *      flags->ce   Enumeration
  189.  *      flags->ck   EnumerationConstant
  190.  *      flags->cu   Union
  191.  *      flags->cv   GlobalVariable
  192.  *      flags->cc   Class
  193.  *      flags->cd   Define
  194.  *
  195.  ---------------------------------------------------------------------------*/
  196.  
  197. BOOLEAN CSymbolWanted(SymbolType type, Flags * flags)
  198. {
  199.     switch (type) {
  200.             case Function:
  201.             if (flags->cf)
  202.                 return TRUE;
  203.             break;
  204.         case ProtoType:
  205.             if (flags->cp)
  206.                 return TRUE;
  207.             break;
  208.         case GlobalVariable:
  209.             if (flags->cv)
  210.                 return TRUE;
  211.             break;
  212.         case Define:
  213.             if (flags->cd)
  214.                 return TRUE;
  215.             break;
  216.         case Macro:
  217.             if (flags->cm)
  218.                 return TRUE;
  219.             break;
  220.         case Structure:
  221.             if (flags->cs)
  222.                 return TRUE;
  223.             break;
  224.         case TypeDefinition:
  225.             if (flags->ct)
  226.                 return TRUE;
  227.             break;
  228.         case Enumeration:
  229.             if (flags->ce)
  230.                 return TRUE;
  231.             break;
  232.         case EnumerationConstant:
  233.             if (flags->ck)
  234.                 return TRUE;
  235.             break;
  236.         case Union:
  237.             if (flags->cu)
  238.                 return TRUE;
  239.             break;
  240.         case Class:
  241.             if (flags->cc)
  242.                 return TRUE;
  243.             break;
  244.         default:
  245.             return FALSE;
  246.             break;
  247.     }
  248.  
  249.     /* not reached */
  250.     return FALSE;
  251. }
  252.  
  253.  
  254. /*----------------------------------------------------------------------------
  255.  *
  256.  * CTokenType() takes the token passed and determines if the token is a
  257.  * special token.  Special tokens require specialized handling in the parser.
  258.  * The function returns the type of token according to the SymbolTypeEnum
  259.  * enumeration.  This routine can only tell so much from one symbol but will
  260.  * return some type for all the *interesting* tokens.  Anything that is
  261.  * loosely defined is given back with the closest type available and the
  262.  * parser must give it contextual meaning
  263.  *
  264.  ---------------------------------------------------------------------------*/
  265.  
  266. SymbolType CTokenType(char *token)
  267. {
  268.     char start[] = "cestu";     /* list of starting characters of symbols */
  269.  
  270.     /* look for dirty rejection */
  271.     if (!strchr(start, token[0]))
  272.         return NOP;
  273.  
  274.     /* structure declarations */
  275.     if (!strcmp(token, "struct"))
  276.         return Structure;
  277.  
  278.     /* type declaration */
  279.     if (!strcmp(token, "typedef"))
  280.         return TypeDefinition;
  281.  
  282.     /* enumeration declaration */
  283.     if (!strcmp(token, "enum"))
  284.         return Enumeration;
  285.  
  286.     /* union declaration */
  287.     if (!strcmp(token, "union"))
  288.         return Union;
  289.  
  290.     /* class declaration */
  291.     if (!strcmp(token, "class"))
  292.         return Class;
  293.  
  294.     /* extern declaration */
  295.     if (!strcmp(token, "extern"))
  296.         return Extern;
  297.  
  298.     /* static declaration */
  299.     if (!strcmp(token, "static"))
  300.         return Static;
  301.  
  302.     /* do not recognize it as anything special */
  303.     return NOP;
  304. }
  305.  
  306.  
  307. /*----------------------------------------------------------------------------
  308.  *
  309.  * CIsDeclarationToken() takes the token passed and determines if the token
  310.  * is a declaration keyword used in C.  The user may define new declaration
  311.  * keywords via use of the typedef keyword.  This alters the syntax of C.  If
  312.  * the syntax is changed in this way it is probable that this routine would
  313.  * not return the correct value.  For the standard uses of this routine that
  314.  * information should not hinder performance for the vast majority of the
  315.  * cases.
  316.  *
  317.  ---------------------------------------------------------------------------*/
  318.  
  319. #define SYMBOL_SIZE 20
  320.  
  321. BOOLEAN CIsDeclarationToken(char *token)
  322. {
  323.     char token_list[][SYMBOL_SIZE] =
  324.     {
  325.         "*ivclsdfuaretp_hn\"",  /* list of starting characters of symbols
  326.                                  * below */
  327.         "*",                    /* pointer */
  328.         "\"C\"",                /* C++ extern for C code */
  329.         "int",                  /* integer declaration */
  330.         "void",                 /* void type */
  331.         "char",                 /* character */
  332.         "long",                 /* long integer */
  333.         "short",                /* short integer */
  334.         "double",               /* double floating point */
  335.         "float",                /* floating point */
  336.         "signed",               /* signed integer */
  337.         "unsigned",             /* unsigned integer */
  338.         "auto",                 /* auto variable (local duration) */
  339.         "register",             /* register variable */
  340.         "static",               /* static variable */
  341.         "struct",               /* structure define */
  342.         "union",                /* union define */
  343.         "enum",                 /* enum defined */
  344.         "typedef",              /* type definition */
  345.         "const",                /* constant variable */
  346.         "extern",               /* external declaration */
  347.         "class",                /* class declaration */
  348.         "friend",               /* class modifier */
  349.         "private",              /* class modifier */
  350.         "protected",            /* class modifier */
  351.         "public",               /* class modifier */
  352.         "volatile",             /* Compiler warning */
  353.         "_based",               /* pointer type */
  354.         "_cdecl",               /* parameter calling sequence, C style */
  355.         "cdecl",                /* parameter calling sequence, C style */
  356.         "_far",                 /* pointer type */
  357.         "far",                  /* pointer type */
  358.         "_huge",                /* pointer type */
  359.         "huge",                 /* pointer type */
  360.         "_near",                /* pointer type */
  361.         "near",                 /* pointer type */
  362.         "_pascal",              /* parameter calling sequence, PASCAL style */
  363.         "pascal",               /* parameter calling sequence, PASCAL style */
  364.         "_fortran",             /* parameter calling sequence, FORTRAN style */
  365.         "_fastcall",            /* parameter calling sequence, via registers */
  366.         "\0"
  367.     };
  368.  
  369.     int index;
  370.  
  371.     /* look for dirty rejection */
  372.     if (!strchr(token_list[0], token[0]))
  373.         return FALSE;
  374.  
  375.     /* march through array until membership is determined */
  376.     for (index = 1; *token_list[index]; (index)++) {
  377.  
  378.         /* return true if token found */
  379.         if (!strcmp(token, token_list[index])) {
  380.             return TRUE;
  381.         }
  382.     }
  383.  
  384.     /* did not find it */
  385.     return FALSE;
  386. }
  387.  
  388.  
  389. /*----------------------------------------------------------------------------
  390.  *
  391.  * COutputToken() will output a token of a given type.  The token is output
  392.  * if the passed token type is requested from the command line.
  393.  *
  394.  ---------------------------------------------------------------------------*/
  395.  
  396. void COutputToken(Token * token, Buffer * token_buffer,
  397.                    SymbolType token_type, FILE * outfile,
  398.                    char *infname, Flags * flags)
  399. {
  400.     char line[MAX_TOKEN_LENGTH];/* the line for use with GNU output format */
  401.  
  402.     long int old_offset;        /* the previous value of the file ptr */
  403.     int line_length;            /* the length of the line */
  404.  
  405.     /* init */
  406.     line[0] = '\0';
  407.  
  408.     /* filter any junk tags */
  409.     if (!IsDelim(token->prev_token[0])) {
  410.  
  411.         /* check that the symbol is wanted and output it if so */
  412.         if (CSymbolWanted(token_type, flags)) {
  413.  
  414.             /* return if external and externals not wanted */
  415.             if (token->extern_active) {
  416.                 if (!flags->cx) {
  417.                     if (token_type != Function &&
  418.                         token_type != Define &&
  419.                         token_type != Macro) {
  420.                         return;
  421.                     }
  422.                 }
  423.             }
  424.  
  425.             /* return if static and statics are not wanted */
  426.             if (token->static_active) {
  427.                 if (!flags->ci) {
  428.                     if (token_type != Define &&
  429.                         token_type != Macro) {
  430.                         return;
  431.                     }
  432.                 }
  433.             }
  434.  
  435.             /* if Epsilon or GNU output is specified then we need to
  436.                output the full line */
  437.             if (flags->og || flags->oe) {
  438.                 /* store the current file offset, move to the line offset, read
  439.                  * the line into a buffer and restore the file offset */
  440.                 old_offset = ftell(token_buffer->infile);
  441.                 if (fseek(token_buffer->infile,
  442.                           *(token->prev_line_offset), SEEK_SET)) {
  443.                     log_message("# COutputToken() -- internal error - continuing");
  444.                 }
  445.                 else {
  446.                     fgets(line, MAX_TOKEN_LENGTH, token_buffer->infile);
  447.                     line_length = strlen(line);
  448.                     if (line[line_length - 1] == '\n') {
  449.                         line[line_length - 1] = '\0';
  450.                     }
  451.                     if (fseek(token_buffer->infile, old_offset, SEEK_SET)) {
  452.                         log_message("# COutputToken() -- internal error - continuing");
  453.                     }
  454.                 }
  455.             }
  456.  
  457.             OutputTag(outfile, line,
  458.                       token->prev_token, infname,
  459.                       *(token->prev_token_line),
  460.                       *(token->prev_char_location) -
  461.                       strlen(token->prev_token), flags);
  462.         }
  463.     }
  464. }
  465.  
  466.  
  467. /*----------------------------------------------------------------------------
  468.  *
  469.  * CGetToken() will obtain the next token in the line pointed to by lptr and
  470.  * in addition will return FALSE if EOL is reached.  This routine is passed
  471.  * an inbut buffer (Cbuf) and a current pointer into the buffer.  It is the
  472.  * responsibility of this routine to refill the buffer if required.  Quoted
  473.  * strings and single quoted characters are returned as a single token.
  474.  * Comments are completely ignored by this parser.  The token will not exceed
  475.  * max_token_length - 1 in length (not including the end of line delimiter)
  476.  *
  477.  ---------------------------------------------------------------------------*/
  478.  
  479. BOOLEAN CGetToken(FILE * infile,
  480.                    char **buffer,
  481.                    char *Cbuf,
  482.                    char *token,
  483.                    int max_token_length,
  484.                    long int *line_number,
  485.                    long int *char_number,
  486.                    long int *line_offset)
  487. {
  488.     typedef enum parser_state { /* a state of the lexical parser */
  489.         Parse, BeginCommentMaybe, InComment, InCommentEndMaybe, InCPPComment,
  490.         InQuoteNormal, InQuoteLiteral, InSingleQuoteNormal,
  491.         InSingleQuoteLiteral, EndSingleQuote, WhiteSpace, Exit
  492.     } State;
  493.  
  494.     State current_state;        /* the current state of the parser */
  495.  
  496.     char c;                     /* the current character being examined */
  497.     char *t;                    /* pointer into token */
  498.  
  499.     int token_length;           /* the current token length cannot exceed max
  500.                                  * token length */
  501.  
  502.     /* init */
  503.     current_state = WhiteSpace;
  504.     t = token;
  505.     *t = '\0';
  506.     token_length = 0;
  507.  
  508.     /* parse the file for the next token */
  509.     while (TRUE) {
  510.  
  511.         c = **buffer;
  512.  
  513.         /* if the buffer has been completely used, refill the buffer, I make
  514.          * the tacit assumption here that the null character is not a member
  515.          * of the source file */
  516.         if (!c) {
  517.             *buffer = Cbuf;
  518.             if (FillBuffer(infile, Cbuf,
  519.                            (long int) CBUFSIZE)) {
  520.                 c = **buffer;
  521.             }
  522.             else {
  523.  
  524.                 /* return the token if it exists */
  525.                 if (t != token) {
  526.                     *t = '\0';
  527.                     return TRUE;
  528.                 }
  529.                 else
  530.                     return FALSE;
  531.             }
  532.         }
  533.  
  534.         /* react on the state machine */
  535.         switch (current_state) {
  536.  
  537.             case Parse:
  538.                 switch (c) {
  539.  
  540.                     case '/':
  541.  
  542.                         /* return if we already have a token */
  543.                         if (t != token) {
  544.                             (*buffer)--;
  545.                             (*char_number)--;
  546.                             current_state = Exit;
  547.                         }
  548.                         else {
  549.                             /* this may be the begin if a comment or the
  550.                              * division symbol, read the next character after
  551.                              * verifying it the buffer doesn't need refilling */
  552.                             current_state = BeginCommentMaybe;
  553.                             *t = c;
  554.                         }
  555.                         break;
  556.  
  557.                     case '\"':
  558.  
  559.                         /* return if we already have a token */
  560.                         if (t != token) {
  561.                             (*buffer)--;
  562.                             (*char_number)--;
  563.                             current_state = Exit;
  564.                         }
  565.                         else {
  566.                             current_state = InQuoteNormal;
  567.                             *t++ = c;
  568.                             token_length++;
  569.                         }
  570.                         break;
  571.  
  572.                     case '\'':
  573.  
  574.                         /* return if we already have a token */
  575.                         if (t != token) {
  576.                             (*buffer)--;
  577.                             (*char_number)--;
  578.                             current_state = Exit;
  579.                         }
  580.                         else {
  581.                             current_state = InSingleQuoteNormal;
  582.                             *t++ = c;
  583.                             token_length++;
  584.                         }
  585.                         break;
  586.  
  587.                     default:
  588.  
  589.                         /* if it is a delimiter than stop processing */
  590.                         if (IsDelim(c)) {
  591.  
  592.                             /* if a token exists then back up in buffer */
  593.                             if (t != token) {
  594.                                 (*buffer)--;
  595.                                 (*char_number)--;
  596.                             }
  597.                             else {
  598.                                 *t++ = c;
  599.                                 token_length++;
  600.                             }
  601.                             current_state = Exit;
  602.                         }
  603.                         else {
  604.  
  605.                             /* normal character, store it in the token */
  606.                             *t++ = c;
  607.                             token_length++;
  608.                         }
  609.                         break;
  610.                 }
  611.                 break;
  612.  
  613.             case WhiteSpace:
  614.  
  615.                 /* pass over whitespace, backup one char if no longer in
  616.                  * white space region */
  617.                 if (!IsWhite(c)) {
  618.                     current_state = Parse;
  619.                     (*buffer)--;
  620.                     (*char_number)--;
  621.                 }
  622.                 else {
  623.  
  624.                     /* check for newline */
  625.                     if (c == '\n') {
  626.                         (*line_number)++;
  627.                         *line_offset = *char_number + *line_number;
  628.                     }
  629.                 }
  630.                 break;
  631.  
  632.             case BeginCommentMaybe:
  633.                 switch (c) {
  634.  
  635.                     case '/':
  636.                         current_state = InCPPComment;
  637.                         break;
  638.  
  639.                     case '*':
  640.                         current_state = InComment;
  641.                         break;
  642.  
  643.                     default:
  644.                         t++;
  645.                         token_length++;
  646.                         (*buffer)--;
  647.                         (*char_number)--;
  648.                         current_state = Exit;
  649.                         break;
  650.                 }
  651.                 break;
  652.  
  653.             case InComment:
  654.                 switch (c) {
  655.  
  656.                     case '*':
  657.                         /* this is potentially the end of the comment */
  658.                         current_state = InCommentEndMaybe;
  659.                         break;
  660.  
  661.                     case '\n':
  662.                         /* new line just increment state variables */
  663.                         (*line_number)++;
  664.                         *line_offset = *char_number + *line_number;
  665.                         break;
  666.  
  667.                     default:
  668.                         break;
  669.                 }
  670.                 break;
  671.  
  672.             case InCommentEndMaybe:
  673.                 switch (c) {
  674.  
  675.                     case '/':
  676.                         /* this is indeed the end of the comment */
  677.                         current_state = WhiteSpace;
  678.                         break;
  679.  
  680.                     case '*':
  681.                         /* this is also perhaps the end of comment */
  682.                         break;
  683.  
  684.                     case '\n':
  685.                         /* new line just increment state variables */
  686.                         (*line_number)++;
  687.                         *line_offset = *char_number + *line_number;
  688.  
  689.                     default:
  690.                         /* still part of the current comment */
  691.                         current_state = InComment;
  692.                         break;
  693.                 }
  694.                 break;
  695.  
  696.             case InCPPComment:
  697.                 if (c == '\n') {
  698.                     current_state = WhiteSpace;
  699.                     (*line_number)++;
  700.                     *line_offset = *char_number + *line_number;
  701.                 }
  702.                 break;
  703.  
  704.             case InQuoteNormal:
  705.                 switch (c) {
  706.  
  707.                     case '\"':
  708.                         /* end of InQuoteNormal state */
  709.                         current_state = Exit;
  710.                         break;
  711.  
  712.                     case '\\':
  713.                         /* InQuoteLiteral state */
  714.                         current_state = InQuoteLiteral;
  715.                         break;
  716.  
  717.                     default:
  718.                         /* normal dull behavior */
  719.                         break;
  720.                 }
  721.                 *t++ = c;
  722.                 token_length++;
  723.                 break;
  724.  
  725.             case InQuoteLiteral:
  726.                 /* this char is simply copied */
  727.                 current_state = InQuoteNormal;
  728.                 *t++ = c;
  729.                 token_length++;
  730.                 break;
  731.  
  732.             case InSingleQuoteNormal:
  733.                 switch (c) {
  734.  
  735.                     case '\\':
  736.                         /* InQuoteLiteral state */
  737.                         current_state = InSingleQuoteLiteral;
  738.                         break;
  739.  
  740.                     default:
  741.                         /* Just copy the character and move to close quote */
  742.                         current_state = EndSingleQuote;
  743.                         break;
  744.                 }
  745.                 *t++ = c;
  746.                 token_length++;
  747.                 break;
  748.  
  749.             case InSingleQuoteLiteral:
  750.                 /* this char is simply copied */
  751.                 current_state = EndSingleQuote;
  752.                 *t++ = c;
  753.                 token_length++;
  754.                 break;
  755.  
  756.             case EndSingleQuote:
  757.  
  758.                 /* end of InSingleQuote states */
  759.                 current_state = Exit;
  760.                 *t++ = c;
  761.                 token_length++;
  762.                 break;
  763.  
  764.             case Exit:
  765.                 *t = '\0';
  766.                 return TRUE;
  767.                 break;
  768.  
  769.             default:            /* not reached */
  770.                 break;
  771.         }
  772.  
  773.         /* if the token_length has gotten too large then return */
  774.         if (token_length == max_token_length - 1) {
  775.             *t = '\0';
  776.             return TRUE;
  777.         }
  778.  
  779.         /* move to the next buffer location */
  780.         (*buffer)++;
  781.         (*char_number)++;
  782.     }
  783. }
  784.  
  785.  
  786. /*----------------------------------------------------------------------------
  787.  *
  788.  * CFillToken() will obtain the next lexical parser from the buffer and move
  789.  * the token into the Token structure.  TRUE is returned if the lexical
  790.  * parser returns TRUE, otherwise FALSE is returned.
  791.  *
  792.  ---------------------------------------------------------------------------*/
  793.  
  794. BOOLEAN CFillToken(Token * token, Buffer * token_buffer)
  795. {
  796.     BOOLEAN token_found;
  797.  
  798.     /* obtain the next token */
  799.     token_found = CGetToken(token_buffer->infile,
  800.                             &(token_buffer->buffer),
  801.                             token_buffer->Cbuf, token->cur_token,
  802.                             MAX_TOKEN_LENGTH,
  803.                             &(token_buffer->token_line_location),
  804.                             &(token_buffer->token_char_location),
  805.                             &(token_buffer->token_line_offset));
  806.  
  807.     /* if one is around then update the state for that token */
  808.     if (token_found) {
  809.         /* update location variables */
  810.         *(token->cur_char_location) =
  811.             token_buffer->token_char_location;
  812.         *(token->cur_token_line) =
  813.             token_buffer->token_line_location;
  814.         *(token->cur_line_offset) =
  815.             token_buffer->token_line_offset;
  816.     }
  817.  
  818.     return token_found;
  819. }
  820.  
  821.  
  822. /*----------------------------------------------------------------------------
  823.  *
  824.  * CTokenSwap() will swap the token variables and set the prev_ variables
  825.  * correctly
  826.  *
  827.  ---------------------------------------------------------------------------*/
  828.  
  829. void CTokenSwap(Token * token)
  830. {
  831.     char *charswap;             /* temporary swap variable */
  832.     long int *longintswap;      /* temporary swap variable */
  833.  
  834.     /* swap the active token string */
  835.     charswap = token->cur_token;
  836.     token->cur_token = token->prev_token;
  837.     token->prev_token = charswap;
  838.  
  839.     /* swap the active character location */
  840.     longintswap = token->cur_char_location;
  841.     token->cur_char_location = token->prev_char_location;
  842.     token->prev_char_location = longintswap;
  843.  
  844.     /* swap the active line */
  845.     longintswap = token->cur_token_line;
  846.     token->cur_token_line = token->prev_token_line;
  847.     token->prev_token_line = longintswap;
  848.  
  849.     /* swap the active line offset */
  850.     longintswap = token->cur_line_offset;
  851.     token->cur_line_offset = token->prev_line_offset;
  852.     token->prev_line_offset = longintswap;
  853. }
  854.  
  855.  
  856. /*----------------------------------------------------------------------------
  857.  *
  858.  * CDiscardLine() will move past all the characters up to the next EOL that
  859.  * is not preceded by a line continuation character.  This routine will
  860.  * return TRUE if there was a '(' character as the first character.  This
  861.  * return value is useful for determining if #defines are macros or simple
  862.  * defines.
  863.  *
  864.  ---------------------------------------------------------------------------*/
  865.  
  866. BOOLEAN
  867. CDiscardLine(FILE * infile, char **buffer, char *Cbuf,
  868.                       long int *line_number, long int *char_number,
  869.                       long int *line_offset)
  870. {
  871.     char c;                     /* the current character being examined */
  872.  
  873.     BOOLEAN line_continue;      /* TRUE if line continuation true */
  874.     BOOLEAN is_macro;           /* TRUE if the first delimiter char is '(' */
  875.     BOOLEAN first_char;         /* TRUE when first character is active */
  876.  
  877.     /* init */
  878.     c = '\0';
  879.     line_continue = FALSE;
  880.     is_macro = FALSE;
  881.     first_char = TRUE;
  882.  
  883.     /* loop until non continued EOL encountered */
  884.     do {
  885.  
  886.         c = **buffer;
  887.         (*buffer)++;
  888.         (*char_number)++;
  889.  
  890.         /* handle the newline */
  891.         if (c == '\n') {
  892.             line_continue = FALSE;
  893.             (*line_number)++;
  894.             *line_offset = *char_number + *line_number - 1;
  895.         }
  896.  
  897.         /* if the buffer has been completely used, refill the buffer, I make
  898.          * the tacit assumption here that the null character is not a member
  899.          * of the source file */
  900.         if (!c) {
  901.             *buffer = Cbuf;
  902.             if (FillBuffer(infile, Cbuf,
  903.                            (long int) CBUFSIZE)) {
  904.                 c = **buffer;
  905.                 (*char_number)--;
  906.             }
  907.             else {
  908.  
  909.                 /* end of file reached */
  910.                 return is_macro;
  911.             }
  912.         }
  913.  
  914.         if (c == '\\')
  915.             line_continue = TRUE;
  916.  
  917.         if (first_char) {
  918.             if (c == '(')
  919.                 is_macro = TRUE;
  920.             first_char = FALSE;
  921.         }
  922.  
  923.     } while (c != '\n' || line_continue);
  924.  
  925.     return is_macro;
  926. }
  927.  
  928.  
  929. /*----------------------------------------------------------------------------
  930.  *
  931.  * CParseDefine() will parse macros and defines in standard C syntax and
  932.  * distinguish between a macro and a define, if there is a punctuator '(' as
  933.  * the first character after the token, then it is a macro.
  934.  *
  935.  ---------------------------------------------------------------------------*/
  936.  
  937. void CParseDefine(Token * token, Buffer * token_buffer,
  938.                    FILE * outfile, char *infname, Flags * flags)
  939. {
  940.     SymbolType tmptype;         /* a temporay type variable */
  941.  
  942.     BOOLEAN token_found;
  943.     BOOLEAN is_macro;
  944.  
  945.     token_found = CFillToken(token, token_buffer);
  946.     if (token_found) {
  947.  
  948.         /* save the previous values */
  949.         CTokenSwap(token);
  950.  
  951.         /* get rid of the rest of the line and return the define type */
  952.         is_macro =
  953.             CDiscardLine(token_buffer->infile,
  954.                          &(token_buffer->buffer),
  955.                          token_buffer->Cbuf,
  956.                          &(token_buffer->token_line_location),
  957.                          &(token_buffer->token_char_location),
  958.                          &(token_buffer->token_line_offset));
  959.  
  960.         /* react on the token */
  961.         if (is_macro) {
  962.             tmptype = Macro;
  963.         }
  964.         else {
  965.             tmptype = Define;
  966.         }
  967.  
  968.         /* output the token */
  969.         COutputToken(token, token_buffer, tmptype,
  970.                      outfile, infname, flags);
  971.     }
  972. }
  973.  
  974.  
  975. /*----------------------------------------------------------------------------
  976.  *
  977.  * CParsePreprocessorDirective() will parse preprocessor directives in
  978.  * standard C syntax
  979.  *
  980.  ---------------------------------------------------------------------------*/
  981.  
  982. void CParsePreprocessorDirective(Token * token, Buffer * token_buffer,
  983.                                FILE * outfile, char *infname, Flags * flags)
  984. {
  985.     BOOLEAN token_found;
  986.  
  987.     token_found = CFillToken(token, token_buffer);
  988.     if (token_found) {
  989.  
  990.         /* deal with a define directive */
  991.         if (!strcmp(token->cur_token, "define")) {
  992.             CParseDefine(token, token_buffer, outfile, infname, flags);
  993.         }
  994.         else {
  995.  
  996.             /* increment the else block level pointer */
  997.             if (!strcmp(token->cur_token, "else")) {
  998.                 token->else_nesting_level++;
  999.             }
  1000.             else {
  1001.                 /* decrement the else block level pointer */
  1002.                 if (!strcmp(token->cur_token, "endif")) {
  1003.                     if (token->else_nesting_level)
  1004.                         token->else_nesting_level--;
  1005.                 }
  1006.                 else {
  1007.  
  1008.                     /* if an else has not already been seen then increment
  1009.                      * the level */
  1010.                     if (!strcmp(token->cur_token, "elif")) {
  1011.                         token->else_nesting_level++;
  1012.                     }
  1013.                 }
  1014.             }
  1015.  
  1016.             /* remove the rest of the directive line including line
  1017.              * continuation characters */
  1018.             CDiscardLine(token_buffer->infile,
  1019.                          &(token_buffer->buffer),
  1020.                          token_buffer->Cbuf,
  1021.                          &(token_buffer->token_line_location),
  1022.                          &(token_buffer->token_char_location),
  1023.                          &(token_buffer->token_line_offset));
  1024.         }
  1025.     }
  1026. }
  1027.  
  1028.  
  1029. /*----------------------------------------------------------------------------
  1030.  *
  1031.  * CNextToken() will obtain the next token in the buffer and update the
  1032.  * appropriate variables.
  1033.  *
  1034.  ---------------------------------------------------------------------------*/
  1035.  
  1036. BOOLEAN CNextToken(Token * token, Buffer * token_buffer, FILE * outfile,
  1037.                     char *infname, Flags * flags)
  1038. {
  1039.     BOOLEAN token_found;
  1040.     BOOLEAN cycle;
  1041.  
  1042.     do {
  1043.         /* obtain the next token */
  1044.         token_found = CFillToken(token, token_buffer);
  1045.  
  1046.         /* check for preprocessing directives and parse them if found */
  1047.         if (token->cur_token[0] == '#' && token_found) {
  1048.  
  1049.             /* parse the directive and loop back to get another token */
  1050.             CParsePreprocessorDirective(token, token_buffer,
  1051.                                         outfile, infname, flags);
  1052.             cycle = TRUE;
  1053.         }
  1054.         else {
  1055.  
  1056.             /* we found a token to pass to the semantic parser */
  1057.             cycle = FALSE;
  1058.         }
  1059.     } while (cycle);
  1060.  
  1061.     /* return it */
  1062.     return token_found;
  1063. }
  1064.  
  1065.  
  1066. /*----------------------------------------------------------------------------
  1067.  *
  1068.  * CToLevelZero() will increment the nesting level and then parse tokens
  1069.  * until level zero has been reached again.  If tokens are no longer
  1070.  * available this loop will stop.
  1071.  *
  1072.  ---------------------------------------------------------------------------*/
  1073.  
  1074. void CToLevelZero(Token * token, Buffer * token_buffer,
  1075.                    FILE * outfile, char *infname, Flags * flags)
  1076. {
  1077.     char open_brace[] = "{[(";  /* open brace set */
  1078.     char close_brace[] = ")]}"; /* close brace set */
  1079.  
  1080.     int nesting_level = 1;
  1081.  
  1082.     token->else_nesting_level = 0;
  1083.  
  1084.     while (nesting_level) {
  1085.         if (CGetToken(token_buffer->infile, &(token_buffer->buffer),
  1086.                       token_buffer->Cbuf, token->cur_token,
  1087.                       MAX_TOKEN_LENGTH,
  1088.                       &(token_buffer->token_line_location),
  1089.                       &(token_buffer->token_char_location),
  1090.                       &(token_buffer->token_line_offset))) {
  1091.             if (token->cur_token[0] == '#') {
  1092.                 CParsePreprocessorDirective(token, token_buffer,
  1093.                                             outfile, infname, flags);
  1094.             }
  1095.             else {
  1096.  
  1097.                 /* only count open brace, parens and brackets within blocks
  1098.                  * of one element of an ifdef code block */
  1099.                 if (!token->else_nesting_level) {
  1100.                     if (strchr(open_brace, token->cur_token[0])) {
  1101.                         nesting_level++;
  1102.                     }
  1103.                     else {
  1104.                         if (strchr(close_brace, token->cur_token[0])) {
  1105.                             nesting_level--;
  1106.                         }
  1107.                     }
  1108.                 }
  1109.             }
  1110.         }
  1111.         else
  1112.             nesting_level = 0;
  1113.     }
  1114. }
  1115.  
  1116.  
  1117. /*----------------------------------------------------------------------------
  1118.  *
  1119.  * CToPunctuator() will parse tokens until the next punctuator has been
  1120.  * reached.  If tokens are no longer available this loop will stop.  If this
  1121.  * loop is successful the found flag declared in the host routine will be
  1122.  * set.
  1123.  *
  1124.  ---------------------------------------------------------------------------*/
  1125.  
  1126. BOOLEAN CToPunctuator(Token * token, Buffer * token_buffer, FILE * outfile,
  1127.                        char *infname, Flags * flags)
  1128. {
  1129.     BOOLEAN punctuator_found;
  1130.  
  1131.     /* init and parse through until the first punctuator is found */
  1132.     token->token_count = 0;
  1133.     punctuator_found = FALSE;
  1134.     while (!punctuator_found) {
  1135.         token->token_count++;
  1136.         CTokenSwap(token);
  1137.         if (!CNextToken(token, token_buffer, outfile, infname, flags)) {
  1138.             break;
  1139.         }
  1140.         else {
  1141.             if (IsPunctuator(token->cur_token[0]))
  1142.                 punctuator_found = TRUE;
  1143.         }
  1144.     }
  1145.  
  1146.     /* return value */
  1147.     return punctuator_found;
  1148. }
  1149.  
  1150.  
  1151. /*----------------------------------------------------------------------------
  1152.  *
  1153.  * CParseParens() will move through a declaration in parentheses and place
  1154.  * the correct valid token as prev_token.  This return TRUE if a '[' was seen
  1155.  * within the parens and false otherwise.
  1156.  *
  1157.  ---------------------------------------------------------------------------*/
  1158.  
  1159. BOOLEAN CParseParens(Token * token, Buffer * token_buffer, FILE * outfile,
  1160.                       char *infname, Flags * flags)
  1161. {
  1162.     BOOLEAN token_found;
  1163.     BOOLEAN variable_seen;
  1164.     int brace_ignore = 1;
  1165.  
  1166.     token->else_nesting_level = 0;
  1167.  
  1168.     token_found = TRUE;
  1169.     variable_seen = FALSE;
  1170.     while (brace_ignore &&
  1171.            token_found) {
  1172.  
  1173.         token_found = CNextToken(token, token_buffer, outfile,
  1174.                                  infname, flags);
  1175.  
  1176.         if (token_found &&
  1177.             !token->else_nesting_level) {
  1178.             switch (token->cur_token[0]) {
  1179.  
  1180.                 case '(':
  1181.  
  1182.                     /* increment brace_ignore and continue */
  1183.                     brace_ignore++;
  1184.                     break;
  1185.  
  1186.                 case ')':
  1187.  
  1188.                     /* just decrement brace_ignore if it is positive. If
  1189.                      * brace ignore is not positive at this point then we
  1190.                      * certainly have a syntax error.  Ignore this fact if
  1191.                      * so. */
  1192.                     if (brace_ignore) {
  1193.                         brace_ignore--;
  1194.                     }
  1195.                     break;
  1196.  
  1197.                 case '[':
  1198.  
  1199.                     /* move to end of array bounds */
  1200.                     variable_seen = TRUE;
  1201.                     CToLevelZero(token, token_buffer, outfile,
  1202.                                  infname, flags);
  1203.                     break;
  1204.  
  1205.                 default:
  1206.                     CTokenSwap(token);
  1207.                     break;
  1208.             }
  1209.         }
  1210.     }
  1211.  
  1212.     return variable_seen;
  1213. }
  1214.  
  1215.  
  1216. /*----------------------------------------------------------------------------
  1217.  *
  1218.  * COutputCommaDelimitedToken() will output a token and then parse the
  1219.  * statement until ';' or ',' is reached.  The token is output if the passed
  1220.  * token type is requested from the command line.
  1221.  *
  1222.  ---------------------------------------------------------------------------*/
  1223.  
  1224. void COutputCommaDelimitedToken(Token * token, Buffer * token_buffer,
  1225.                                  SymbolType token_type, FILE * outfile,
  1226.                                  char *infname, Flags * flags)
  1227. {
  1228.     char open_brace[] = "{[(";  /* open brace set */
  1229.     BOOLEAN punctuator_found;
  1230.  
  1231.     /* output the token */
  1232.     COutputToken(token, token_buffer, token_type,
  1233.                  outfile, infname, flags);
  1234.  
  1235.     /* go to the next list punctuator (',' or ';') */
  1236.     punctuator_found = TRUE;
  1237.     while (token->cur_token[0] != ',' &&
  1238.            token->cur_token[0] != ';' &&
  1239.            punctuator_found) {
  1240.         if (strchr(open_brace, token->cur_token[0])) {
  1241.             CToLevelZero(token, token_buffer, outfile, infname, flags);
  1242.         }
  1243.         punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1244.                                          infname, flags);
  1245.     }
  1246. }
  1247.  
  1248.  
  1249. /*----------------------------------------------------------------------------
  1250.  *
  1251.  * CParseCommaDelimitedList() will parse a token list seperated by commas
  1252.  * until a ';' is found.  The tokens are output if the passed type is
  1253.  * requested from the command line.
  1254.  *
  1255.  ---------------------------------------------------------------------------*/
  1256.  
  1257. void CParseCommaDelimitedList(Token * token, Buffer * token_buffer,
  1258.                                SymbolType token_type, FILE * outfile,
  1259.                                char *infname, Flags * flags)
  1260. {
  1261.     char open_brace[] = "{[(";  /* open brace set */
  1262.     BOOLEAN punctuator_found;
  1263.  
  1264.     /* parse through the list */
  1265.     punctuator_found = TRUE;
  1266.     while (token->cur_token[0] != ';' &&
  1267.            punctuator_found) {
  1268.         punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1269.                                          infname, flags);
  1270.         if (punctuator_found) {
  1271.             switch (token->cur_token[0]) {
  1272.  
  1273.                 case '(':
  1274.  
  1275.                     /* this is an embedded variable declaration, either a
  1276.                      * complex variable pointer or function pointer, fall
  1277.                      * through after picking out the internal token */
  1278.                     CParseParens(token, token_buffer, outfile,
  1279.                                  infname, flags);
  1280.  
  1281.                 case '[':
  1282.                 case ',':
  1283.                 case ';':
  1284.                 case '=':
  1285.  
  1286.                     /* this is one of the proper ending tokens for this type
  1287.                      * of declaration list, so output it and parse to the
  1288.                      * next correct punctuator */
  1289.                     COutputToken(token, token_buffer, token_type,
  1290.                                  outfile, infname, flags);
  1291.                     while (token->cur_token[0] != ',' &&
  1292.                            token->cur_token[0] != ';' &&
  1293.                            punctuator_found) {
  1294.                         if (strchr(open_brace, token->cur_token[0])) {
  1295.                             CToLevelZero(token, token_buffer, outfile,
  1296.                                          infname, flags);
  1297.                         }
  1298.                         punctuator_found = CToPunctuator(token, token_buffer,
  1299.                                                          outfile, infname,
  1300.                                                          flags);
  1301.                     }
  1302.                     break;
  1303.                 default:
  1304.                     break;
  1305.             }
  1306.         }
  1307.     }
  1308. }
  1309.  
  1310.  
  1311. /*----------------------------------------------------------------------------
  1312.  *
  1313.  * CParseFunctionOrGlobalVariable() will parse a function, prototype or
  1314.  * global variable syntax.
  1315.  *
  1316.  ---------------------------------------------------------------------------*/
  1317.  
  1318. void CParseFunctionOrGlobalVariable(Token * token, Buffer * token_buffer,
  1319.                                      FILE * outfile, char *infname,
  1320.                                      Flags * flags)
  1321. {
  1322.     char buf[MAX_TOKEN_LENGTH]; /* the first token buffer */
  1323.     long int charloc;           /* the char location of sbuf1 */
  1324.     long int tokenline;         /* the line number of sbuf1 */
  1325.     long int lineoffset;        /* the line offset of sbuf1 */
  1326.  
  1327.     BOOLEAN token_found;
  1328.     BOOLEAN punctuator_found;
  1329.     BOOLEAN last_token_known;
  1330.     BOOLEAN variable_seen;
  1331.  
  1332.     /* init */
  1333.     buf[0] = '\0';
  1334.     charloc = 0;
  1335.     tokenline = 1;
  1336.     lineoffset = 0;
  1337.  
  1338.     /* save the previous token */
  1339.     last_token_known = CIsDeclarationToken(token->prev_token);
  1340.     if (!last_token_known) {
  1341.  
  1342.         /* If this is not a known token then it may be a function name. Save
  1343.          * it then look further at the syntax.  This also may be a symbol
  1344.          * previously defined via a typedef which alters the syntax of C/C++ */
  1345.         strcpy(buf, token->prev_token);
  1346.         charloc = *(token->prev_char_location);
  1347.         tokenline = *(token->prev_token_line);
  1348.         lineoffset = *(token->prev_line_offset);
  1349.     }
  1350.  
  1351.     /* This is a function or prototype or global variable go to brace_ignore
  1352.      * level zero again. */
  1353.     variable_seen = CParseParens(token, token_buffer, outfile,
  1354.                                  infname, flags);
  1355.  
  1356.     /* Check to see if this is a function, prototype, or global variable. If
  1357.      * the token is a ';' and last_token_known is false then we assume a
  1358.      * function.  Strange variable declarations may fool this, but not
  1359.      * likely. If the character is a '(' then it is certainly a function or
  1360.      * prototype unless variable_seen is TRUE, then it is a variable. If the
  1361.      * character is a '[', ',' then it is certainly a variable declaration.
  1362.      * If the character is a ';' and last_token_known is true then it is a
  1363.      * variable declaration.  If the token is anything else then it is a
  1364.      * function. */
  1365.     token_found = CNextToken(token, token_buffer, outfile, infname, flags);
  1366.     if (token_found) {
  1367.         switch (token->cur_token[0]) {
  1368.  
  1369.             case ';':
  1370.  
  1371.                 /* determine if a prototype or a variable declaration. if the
  1372.                  * last_token_known is true then it is a global variable.  If
  1373.                  * the token was a symbol defined by a typedef then this
  1374.                  * distinction is incorrect since typedef actually alters
  1375.                  * syntax.  This is correct for the large majority of cases
  1376.                  * since most do not enclose simple variable declarations in
  1377.                  * parens. */
  1378.                 if (last_token_known) {
  1379.  
  1380.                     /* this is a global variable */
  1381.                     COutputToken(token, token_buffer, GlobalVariable,
  1382.                                  outfile, infname, flags);
  1383.                 }
  1384.                 else {
  1385.  
  1386.                     /* this is a prototype, copy saved token back to
  1387.                      * prev_token, output and continue */
  1388.                     strcpy(token->prev_token, buf);
  1389.                     *(token->prev_char_location) = charloc;
  1390.                     *(token->prev_token_line) = tokenline;
  1391.                     *(token->prev_line_offset) = lineoffset;
  1392.                     COutputToken(token, token_buffer, ProtoType,
  1393.                                  outfile, infname, flags);
  1394.                 }
  1395.                 break;
  1396.  
  1397.             case '(':
  1398.  
  1399.                 if (variable_seen) {
  1400.  
  1401.                     /* this is a variable declaration */
  1402.                     COutputCommaDelimitedToken(token, token_buffer,
  1403.                                                GlobalVariable, outfile,
  1404.                                                infname, flags);
  1405.                     CParseCommaDelimitedList(token, token_buffer,
  1406.                                              GlobalVariable, outfile,
  1407.                                              infname, flags);
  1408.                 }
  1409.                 else {
  1410.  
  1411.                     /* move to level zero again */
  1412.                     CToLevelZero(token, token_buffer, outfile,
  1413.                                  infname, flags);
  1414.  
  1415.                     /* obtain the next token */
  1416.                     token_found = CNextToken(token, token_buffer, outfile,
  1417.                                              infname, flags);
  1418.  
  1419.                     if (token_found) {
  1420.  
  1421.                         /* check if prototype, function or function pointer
  1422.                          * variable declaration */
  1423.                         switch (token->cur_token[0]) {
  1424.  
  1425.                             case '=':
  1426.  
  1427.                                 /* this is a function pointer variable
  1428.                                  * declaration */
  1429.                                 COutputCommaDelimitedToken(token,
  1430.                                                            token_buffer,
  1431.                                                            GlobalVariable,
  1432.                                                            outfile,
  1433.                                                            infname, flags);
  1434.                                 CParseCommaDelimitedList(token, token_buffer,
  1435.                                                          GlobalVariable,
  1436.                                                          outfile,
  1437.                                                          infname, flags);
  1438.                                 break;
  1439.  
  1440.                             case ';':
  1441.  
  1442.                                 /* this is a prototype, output it */
  1443.                                 COutputToken(token, token_buffer, ProtoType,
  1444.                                              outfile, infname, flags);
  1445.                                 break;
  1446.  
  1447.                             default:
  1448.  
  1449.                                 /* this is a function */
  1450.                                 COutputToken(token, token_buffer, Function,
  1451.                                              outfile, infname, flags);
  1452.  
  1453.                                 /* parse through function */
  1454.                                 punctuator_found = TRUE;
  1455.                                 while (token->cur_token[0] != '{' &&
  1456.                                        punctuator_found) {
  1457.                                     punctuator_found =
  1458.                                         CToPunctuator(token, token_buffer,
  1459.                                                       outfile, infname,
  1460.                                                       flags);
  1461.                                 }
  1462.                                 if (punctuator_found) {
  1463.                                     CToLevelZero(token, token_buffer, outfile,
  1464.                                                  infname, flags);
  1465.                                 }
  1466.                                 break;
  1467.                         }
  1468.                     }
  1469.                 }
  1470.                 break;
  1471.  
  1472.             case '[':
  1473.             case '=':
  1474.             case ',':
  1475.  
  1476.                 /* global variables */
  1477.                 COutputCommaDelimitedToken(token, token_buffer,
  1478.                                            GlobalVariable, outfile,
  1479.                                            infname, flags);
  1480.                 CParseCommaDelimitedList(token, token_buffer,
  1481.                                          GlobalVariable, outfile,
  1482.                                          infname, flags);
  1483.                 break;
  1484.  
  1485.             default:
  1486.  
  1487.                 /* this is a function, copy saved token back to prev_token,
  1488.                  * output and continue */
  1489.                 strcpy(token->prev_token, buf);
  1490.                 *(token->prev_char_location) = charloc;
  1491.                 *(token->prev_token_line) = tokenline;
  1492.                 *(token->prev_line_offset) = lineoffset;
  1493.                 COutputToken(token, token_buffer, Function,
  1494.                              outfile, infname, flags);
  1495.  
  1496.                 /* parse through function */
  1497.                 punctuator_found = TRUE;
  1498.                 while (token->cur_token[0] != '{' &&
  1499.                        punctuator_found) {
  1500.                     punctuator_found =
  1501.                         CToPunctuator(token, token_buffer, outfile,
  1502.                                       infname, flags);
  1503.                 }
  1504.                 if (punctuator_found) {
  1505.                     CToLevelZero(token, token_buffer, outfile,
  1506.                                  infname, flags);
  1507.                 }
  1508.                 break;
  1509.         }
  1510.     }
  1511. }
  1512.  
  1513.  
  1514. /*----------------------------------------------------------------------------
  1515.  *
  1516.  * CParseNOP() will parse an as of yet unrecognized statement.  If I run into
  1517.  * a punctuator at this time then I have found either a structure declaration
  1518.  * (C++ 2.0), or a global variable declaration.  If the punctuator is '[',
  1519.  * ',', '=', or ';' then it is a global variable declaration.  If the
  1520.  * punctuator is a '{' then we have a structure declaration at this time we
  1521.  * should not run into any closing punctuators or syntax is in a bad way
  1522.  *
  1523.  ---------------------------------------------------------------------------*/
  1524.  
  1525. void CParseNOP(Token * token, Buffer * token_buffer, FILE * outfile,
  1526.                 char *infname, Flags * flags)
  1527. {
  1528.     BOOLEAN token_found;
  1529.  
  1530.     switch (token->cur_token[0]) {
  1531.         case ';':
  1532.         case '=':
  1533.         case ',':
  1534.         case '[':
  1535.  
  1536.             /* global variables are here */
  1537.             COutputCommaDelimitedToken(token, token_buffer,
  1538.                                        GlobalVariable, outfile,
  1539.                                        infname, flags);
  1540.             CParseCommaDelimitedList(token, token_buffer,
  1541.                                      GlobalVariable, outfile,
  1542.                                      infname, flags);
  1543.             token->extern_active = FALSE;
  1544.             token->CPP_extern_active = FALSE;
  1545.             token->static_active = FALSE;
  1546.             break;
  1547.  
  1548.         case '{':
  1549.                 
  1550.             /* validate we are not in a C++ extern for C statements */
  1551.             if (!token->CPP_extern_active) {
  1552.                 
  1553.                 /* this is a structure (C++ syntax) */
  1554.                 /* output it */
  1555.                 COutputToken(token, token_buffer, Structure,
  1556.                              outfile, infname, flags);
  1557.  
  1558.                 /* move through declaration */
  1559.                 CToLevelZero(token, token_buffer, outfile, infname, flags);
  1560.  
  1561.                 /* get the next token */
  1562.                 token_found = CNextToken(token, token_buffer, outfile,
  1563.                                          infname, flags);
  1564.  
  1565.                 /* if a token is available then output the list */
  1566.                 if (token_found) {
  1567.                     CParseCommaDelimitedList(token, token_buffer,
  1568.                                              GlobalVariable, outfile,
  1569.                                              infname, flags);
  1570.                 }                                                      
  1571.                 token->extern_active = FALSE;
  1572.                 token->static_active = FALSE;
  1573.             }
  1574.             
  1575.             break;
  1576.  
  1577.         case '(':
  1578.  
  1579.             CParseFunctionOrGlobalVariable(token, token_buffer, outfile,
  1580.                                            infname, flags);
  1581.             token->extern_active = FALSE;
  1582.             token->CPP_extern_active = FALSE;
  1583.             token->static_active = FALSE;
  1584.             break;
  1585.  
  1586.         case '"':
  1587.                                             
  1588.             if (!strcmp("\"C\"",token->cur_token))
  1589.                 token->CPP_extern_active = TRUE;
  1590.             break;
  1591.             
  1592.         default:
  1593.  
  1594.             /* true NOP */
  1595.             break;
  1596.     }
  1597. }
  1598.  
  1599.  
  1600. /*----------------------------------------------------------------------------
  1601.  *
  1602.  * CParseEnumerationConstants() will parse constants within an enumeration
  1603.  * declaration 
  1604.  *
  1605.  ---------------------------------------------------------------------------*/
  1606.  
  1607. void CParseEnumerationConstants(Token *token, Buffer *token_buffer, 
  1608.                                 FILE *outfile, char *infname, 
  1609.                                 Flags *flags)
  1610. {        
  1611.     BOOLEAN punctuator_found;
  1612.  
  1613.     char open_brace[] = "({[";
  1614.     
  1615.     /* obtain the enumeration constants */
  1616.     punctuator_found = TRUE;
  1617.     
  1618.     while (token->cur_token[0] != '}' &&
  1619.            punctuator_found) {
  1620.         punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1621.                                          infname, flags);
  1622.         if (punctuator_found) {
  1623.             switch (token->cur_token[0]) {
  1624.  
  1625.                 case ',':
  1626.                 case '=':
  1627.  
  1628.                     /* this is one of the proper ending tokens for this type
  1629.                      * of declaration list, so output it and parse to the
  1630.                      * next correct punctuator */
  1631.                     COutputToken(token, token_buffer, EnumerationConstant,
  1632.                                  outfile, infname, flags);
  1633.                     while (token->cur_token[0] != ',' &&
  1634.                            token->cur_token[0] != '}' &&
  1635.                            punctuator_found) {
  1636.                         if (strchr(open_brace, token->cur_token[0])) {
  1637.                             CToLevelZero(token, token_buffer, outfile,
  1638.                                          infname, flags);
  1639.                         }
  1640.                         punctuator_found = CToPunctuator(token, token_buffer,
  1641.                                                          outfile, infname,
  1642.                                                          flags);
  1643.                     }
  1644.                     break;
  1645.                     
  1646.                 default:
  1647.                     break;
  1648.             }
  1649.         }
  1650.     }
  1651. }
  1652.     
  1653.  
  1654. /*----------------------------------------------------------------------------
  1655.  *
  1656.  * CParseDeclarationStatement() will parse struct, enum and union
  1657.  * declarations.  take the token just before the first punctuator, run
  1658.  * through the top level braces and parse for variables if the first
  1659.  * punctuator is a ';' then this is a global variable declaration, if the
  1660.  * first token[0] is a '{' then this is a global variable declaration.
  1661.  *
  1662.  ---------------------------------------------------------------------------*/
  1663.  
  1664. void CParseDeclarationStatement(Token * token, Buffer * token_buffer,
  1665.                                  SymbolType type, FILE * outfile,
  1666.                                  char *infname, Flags * flags)
  1667. {
  1668.     BOOLEAN token_found;
  1669.     BOOLEAN punctuator_found;
  1670.     BOOLEAN primary_parse;
  1671.  
  1672.     punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1673.                                      infname, flags);
  1674.     if (punctuator_found) {
  1675.  
  1676.         /* init */
  1677.         primary_parse = TRUE;
  1678.  
  1679.         /* switch on current token */
  1680.         switch (token->cur_token[0]) {
  1681.  
  1682.                 /* this is truly an object declaration */
  1683.             case '{':
  1684.  
  1685.                 /* output only if this is not a variable declaration */
  1686.                 if (token->token_count != 1) {
  1687.  
  1688.                     /* output it */
  1689.                     COutputToken(token, token_buffer, type,
  1690.                                  outfile, infname, flags);
  1691.                 }
  1692.  
  1693.                 /* check if enumeration */
  1694.                 if (type == Enumeration) {
  1695.  
  1696.                     CParseEnumerationConstants(token, token_buffer, 
  1697.                                                outfile, infname, flags);
  1698.                 }
  1699.                 else {
  1700.  
  1701.                     /* move through declaration and fall through */
  1702.                     CToLevelZero(token, token_buffer, outfile, infname, flags);
  1703.                 }
  1704.  
  1705.                 /* get the next token, if one not available then break out of
  1706.                  * case */
  1707.                 token_found = CNextToken(token, token_buffer, outfile,
  1708.                                          infname, flags);
  1709.                 if (!token_found)
  1710.                     break;
  1711.  
  1712.                 /* fall through to take care of variable declarations after
  1713.                  * setting pre-parse flag */
  1714.                 primary_parse = FALSE;
  1715.  
  1716.             case ';':
  1717.             case '=':
  1718.             case ',':
  1719.             case '[':
  1720.  
  1721.                 /* if this is the first seen then output it */
  1722.                 if (primary_parse) {
  1723.                     COutputCommaDelimitedToken(token, token_buffer,
  1724.                                                GlobalVariable,
  1725.                                                outfile, infname,
  1726.                                                flags);
  1727.                 }
  1728.  
  1729.                 CParseCommaDelimitedList(token, token_buffer,
  1730.                                          GlobalVariable,
  1731.                                          outfile, infname,
  1732.                                          flags);
  1733.  
  1734.                 break;
  1735.  
  1736.             case '(':
  1737.  
  1738.                 CParseFunctionOrGlobalVariable(token, token_buffer,
  1739.                                                outfile, infname, flags);
  1740.                 break;
  1741.  
  1742.             default:
  1743.  
  1744.                 /* not reached */
  1745.                 break;
  1746.         }
  1747.     }
  1748. }
  1749.  
  1750.  
  1751. /*----------------------------------------------------------------------------
  1752.  *
  1753.  * CParseTypeDefinition() parses the typedef statement.  take the token just
  1754.  * before the first *correct* punctuator, the ';', ',' or the '['.  Tag any
  1755.  * declarations being done here, get the next token
  1756.  *
  1757.  ---------------------------------------------------------------------------*/
  1758.  
  1759. void CParseTypeDefinition(Token * token, Buffer * token_buffer, FILE * outfile,
  1760.                            char *infname, Flags * flags)
  1761. {
  1762.     BOOLEAN token_found;
  1763.     BOOLEAN parens_found;
  1764.     BOOLEAN special_found;
  1765.  
  1766.     int token_count;
  1767.     SymbolType tmptype;
  1768.  
  1769.     token_found = CNextToken(token, token_buffer, outfile, infname, flags);
  1770.  
  1771.     if (token_found) {
  1772.  
  1773.         /* check the type of the token for future use */
  1774.         tmptype = CTokenType(token->cur_token);
  1775.  
  1776.         /* parse the typedef */
  1777.         parens_found = FALSE;
  1778.         special_found = FALSE;
  1779.         token_count = 0;
  1780.         while (token->cur_token[0] != ';' &&
  1781.                token->cur_token[0] != ',' &&
  1782.                token->cur_token[0] != '[' &&
  1783.                token_found &&
  1784.                !special_found) {
  1785.  
  1786.             /* parse for defines */
  1787.             if (token_found) {
  1788.  
  1789.                 /* handle the punctuators */
  1790.                 switch (token->cur_token[0]) {
  1791.  
  1792.                     case '{':
  1793.  
  1794.                         /* pass through any defines going on here */
  1795.                         if (token->cur_token[0] == '{') {
  1796.  
  1797.                             /* if the token count is > 1 here then we have a
  1798.                              * named declaration and need to output the
  1799.                              * token, output only if the token type is enum,
  1800.                              * struct, or union */
  1801.                             if (token_count > 1 &&
  1802.                                 (tmptype == Structure ||
  1803.                                  tmptype == Enumeration ||
  1804.                                  tmptype == Union)) {
  1805.                                 COutputToken(token, token_buffer,
  1806.                                              tmptype, outfile,
  1807.                                              infname, flags);
  1808.                             }
  1809.  
  1810.                             if (tmptype == Enumeration) {
  1811.  
  1812.                                 CParseEnumerationConstants(token,
  1813.                                                            token_buffer, 
  1814.                                                            outfile, infname, 
  1815.                                                            flags);
  1816.                             }
  1817.                             else {
  1818.  
  1819.                                 /* go back to level 0 */
  1820.                                 CToLevelZero(token, token_buffer, outfile,
  1821.                                              infname, flags);
  1822.                             }
  1823.                         }
  1824.                         break;
  1825.  
  1826.                     case '(':
  1827.  
  1828.                         /* if this is the top level and we have already been
  1829.                          * through a set of parens then we know this to be a
  1830.                          * function typedef so we output the previous token,
  1831.                          * otherwise check the previous token and if it is a
  1832.                          * known keyword then just eat the token and continue
  1833.                          * on our way */
  1834.                         if (parens_found) {
  1835.                             COutputToken(token, token_buffer,
  1836.                                          TypeDefinition, outfile,
  1837.                                          infname, flags);
  1838.                             CToLevelZero(token, token_buffer, outfile,
  1839.                                          infname, flags);
  1840.                             special_found = TRUE;
  1841.                         }
  1842.                         else {
  1843.  
  1844.                             /* Move back to the top level */
  1845.                             CParseParens(token, token_buffer, outfile,
  1846.                                          infname, flags);
  1847.  
  1848.                             /* next paren we find we know we have a token */
  1849.                             parens_found = TRUE;
  1850.  
  1851.                             /* swap to prevent loss of token */
  1852.                             CTokenSwap(token);
  1853.                         }
  1854.                         break;
  1855.  
  1856.                     default:
  1857.  
  1858.                         /* if we have another token after a paren parse then
  1859.                          * we know the token in the parens was nothing
  1860.                          * special */
  1861.                         parens_found = FALSE;
  1862.                         break;
  1863.                 }
  1864.             }
  1865.  
  1866.             /* get another token */
  1867.             CTokenSwap(token);
  1868.             token_found = CNextToken(token, token_buffer, outfile,
  1869.                                      infname, flags);
  1870.             token_count++;
  1871.         }
  1872.  
  1873.         /* output the typedef names if appropriate */
  1874.         if (token->prev_token[0] != '}' &&
  1875.             token_found) {
  1876.  
  1877.             /* don't output the first token if already done */
  1878.             if (!special_found) {
  1879.                 COutputCommaDelimitedToken(token, token_buffer,
  1880.                                            TypeDefinition, outfile,
  1881.                                            infname, flags);
  1882.             }
  1883.  
  1884.             /* parse through the rest of the typedef names */
  1885.             CParseCommaDelimitedList(token, token_buffer,
  1886.                                      TypeDefinition, outfile,
  1887.                                      infname, flags);
  1888.         }
  1889.     }
  1890. }
  1891.  
  1892.  
  1893. /*----------------------------------------------------------------------------
  1894.  *
  1895.  * CParseClass() will parse the C++ class syntax.  take the token just before
  1896.  * the first '{', ',' or ':' and run through the top level braces if there
  1897.  *
  1898.  ---------------------------------------------------------------------------*/
  1899.  
  1900. void CParseClass(Token * token, Buffer * token_buffer, FILE * outfile,
  1901.                   char *infname, Flags * flags)
  1902. {
  1903.     BOOLEAN token_found;
  1904.  
  1905.     token_found = TRUE;
  1906.     while (token->cur_token[0] != '{' &&
  1907.            token->cur_token[0] != ':' &&
  1908.            token->cur_token[0] != ';' &&
  1909.            token_found) {
  1910.  
  1911.         /* save the current token */
  1912.         CTokenSwap(token);
  1913.  
  1914.         /* get the next token */
  1915.         token_found = CNextToken(token, token_buffer, outfile,
  1916.                                  infname, flags);
  1917.     }
  1918.  
  1919.     /* output the class name */
  1920.     if (token_found) {
  1921.         COutputToken(token, token_buffer, Class,
  1922.                      outfile, infname, flags);
  1923.  
  1924.         /* parse through the remainder of the statement */
  1925.         while (token->cur_token[0] != ';' &&
  1926.                token_found) {
  1927.             if (token->cur_token[0] == '{') {
  1928.  
  1929.                 /* move back to the zero level */
  1930.                 CToLevelZero(token, token_buffer, outfile, infname, flags);
  1931.             }
  1932.  
  1933.             token_found = CNextToken(token, token_buffer, outfile,
  1934.                                      infname, flags);
  1935.         }
  1936.     }
  1937. }
  1938.  
  1939.  
  1940. /*----------------------------------------------------------------------------
  1941.  *
  1942.  * CTags() tags an input stream assuming standard ANSI 2.0 C/C++ syntax.
  1943.  * Long tokens are allowed, ANSI requires only 31 significant.
  1944.  *
  1945.  ---------------------------------------------------------------------------*/
  1946.  
  1947. void CTags(FILE * infile, char *infname, FILE * outfile, Flags * flags)
  1948. {
  1949.     SymbolType type;            /* the type of the current token */
  1950.  
  1951.     Buffer input_buffer;        /* the file buffer and state, stack alloc */
  1952.     Buffer *token_buffer = &input_buffer;       /* a convenient pointer */
  1953.  
  1954.     Token token_state;          /* the token state, stack alloc */
  1955.     Token *token = &token_state;/* a convenient pointer to token state */
  1956.  
  1957.     BOOLEAN token_found;        /* set by CNextToken() */
  1958.  
  1959.     /* init the parser engine */
  1960.     CParserInit();
  1961.     token->token_count = 0;
  1962.  
  1963.     /* init the current token buffers */
  1964.     token->cur_token = token->sbuf1;
  1965.     token->cur_char_location = &(token->charloc1);
  1966.     token->cur_token_line = &(token->tokenline1);
  1967.     token->cur_token[0] = '\0';
  1968.     token->cur_line_offset = &(token->lineoffset1);
  1969.     *(token->cur_char_location) = 0;
  1970.     *(token->cur_token_line) = 1;
  1971.     *(token->cur_line_offset) = 0;
  1972.  
  1973.     /* init the previous token buffers */
  1974.     token->prev_token = token->sbuf2;
  1975.     token->prev_char_location = &(token->charloc2);
  1976.     token->prev_token_line = &(token->tokenline2);
  1977.     token->prev_token[0] = '\0';
  1978.     token->prev_line_offset = &(token->lineoffset2);
  1979.     *(token->prev_char_location) = 0;
  1980.     *(token->prev_token_line) = 1;
  1981.     *(token->prev_line_offset) = 0;
  1982.  
  1983.     /* init the input buffers */
  1984.     token_buffer->token_char_location = 0;
  1985.     token_buffer->token_line_location = 1;
  1986.     token_buffer->token_line_offset = 0;
  1987.     token_buffer->Cbuf[0] = '\0';
  1988.     token_buffer->buffer = token_buffer->Cbuf;
  1989.     token_buffer->infile = infile;
  1990.  
  1991.     /* init Extern and Static states */
  1992.     token->extern_active = FALSE;
  1993.     token->CPP_extern_active = FALSE;
  1994.     token->static_active = FALSE;
  1995.  
  1996.     /* get the first token */
  1997.     token_found = CNextToken(token, token_buffer, outfile, infname, flags);
  1998.  
  1999.     /* loop through the file */
  2000.     while (token_found) {
  2001.  
  2002.         /* obtain the token type */
  2003.         type = CTokenType(token->cur_token);
  2004.  
  2005.         /* react on the token type */
  2006.         switch (type) {
  2007.  
  2008.             case NOP:
  2009.                 CParseNOP(token, token_buffer, outfile, infname, flags);
  2010.                 break;
  2011.  
  2012.             case Structure:
  2013.             case Enumeration:
  2014.             case Union:
  2015.                 CParseDeclarationStatement(token, token_buffer, type,
  2016.                                            outfile, infname, flags);
  2017.                 break;
  2018.  
  2019.             case TypeDefinition:
  2020.                 CParseTypeDefinition(token, token_buffer, outfile,
  2021.                                      infname, flags);
  2022.                 break;
  2023.  
  2024.             case Class:
  2025.                 CParseClass(token, token_buffer, outfile, infname, flags);
  2026.                 break;
  2027.  
  2028.             case Extern:
  2029.                 token->extern_active = TRUE;
  2030.                 break;
  2031.  
  2032.             case Static:
  2033.                 token->static_active = TRUE;
  2034.                 break;
  2035.  
  2036.             default:
  2037.                 /* not reached */
  2038.                 break;
  2039.         }
  2040.  
  2041.         if (type != Extern &&
  2042.             type != Static &&
  2043.             type != NOP) {
  2044.  
  2045.             /* turn off the extern and static flag */
  2046.             token->extern_active = FALSE;
  2047.             token->CPP_extern_active = FALSE;
  2048.             token->static_active = FALSE;
  2049.         }
  2050.  
  2051.         /* swap state variables and get the next token */
  2052.         CTokenSwap(token);
  2053.         token_found = CNextToken(token, token_buffer, outfile,
  2054.                                  infname, flags);
  2055.     }
  2056. }
  2057.